﻿Public Class Tablero
    Private ReadOnly _host As HostHelper
    Private ReadOnly _casilla(,) As Casilla
    Private ReadOnly _barco As List(Of Barco)

    Public Sub New(host As HostHelper)
        _host = host

        ReDim _casilla(Ancho, Alto)
        _barco = New List(Of Barco)

        ' crea las casillas
        For x As Integer = 0 To Ancho - 1
            For y As Integer = 0 To Alto - 1
                _casilla(x, y) = New Casilla(New Point(x, y), TipoContenido.Agua)
            Next
        Next

        ' crea los barcos
        CreaBarcos()

        If _host = P2PEncapsulado.HostPropio Then
            ' distribuye los barcos
            DistribuyeBarcos()
        End If

    End Sub

    Public ReadOnly Property GetInfoCasilla(ByVal posicion As Point) As Casilla
        Get
            Return _casilla(posicion.X, posicion.Y)
        End Get
    End Property

    'Public ReadOnly Property HayBarco (p As Point) As Boolean
    '    Get
    '        Return _casilla (p.X, p.Y).HayBarco
    '    End Get
    'End Property

    Private Sub CreaBarcos()
        Dim id As Integer = 0
        CreaBarcosConjunto(id, BarcosDeCuatroCasillas, TipoBarco.CuatroCasillas)
        CreaBarcosConjunto(id, BarcosDeTresCasillas, TipoBarco.TresCasillas)
        CreaBarcosConjunto(id, BarcosDeDosCasillas, TipoBarco.DosCasillas)
        CreaBarcosConjunto(id, BarcosDeUnaCasilla, TipoBarco.UnaCasilla)
    End Sub

    Private Sub CreaBarcosConjunto(ByRef id As Integer, cantidad As Integer, tipo As TipoBarco)
        For i = 0 To cantidad - 1
            _barco.Add(New Barco(id, tipo))
            id = id + 1
        Next
    End Sub

    ''' <summary>
    ''' Algoritmo que distribuye n barcos en el tablero
    ''' Las siguientes reglas deben cumplirse:
    ''' - la distancia entre dos o más barcos en cualquier dirección ha de ser siempre una casilla de agua
    ''' - los barcos pueden estar pegados a los bordes del tablero
    ''' - el número de barcos de cada tipo ha de cumplirse
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub DistribuyeBarcos()
        For Each b As Barco In _barco
            Dim posicionInicial As Point
            Dim orientación As TipoOrientación = TipoOrientación.Horizontal
            Do
                posicionInicial = UnaPosicionAlAzar()
                ' Debug.Print (posicionInicial.X.ToString + ", " + posicionInicial.Y.ToString)
                If UnRandom(2) = 1 Then
                    orientación = TipoOrientación.Vertical
                End If
            Loop Until Colocarlo(posicionInicial, orientación, b)
        Next
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="posicion"></param>
    ''' <param name="orientación"></param>
    ''' <param name="b"></param>
    ''' <returns></returns>
    ''' <remarks>dos pasadas. una para comprobar y otra para colocar</remarks>
    Private Function Colocarlo(posicion As Point, orientación As TipoOrientación, b As Barco) As Boolean
        If orientación <> TipoOrientación.Horizontal And orientación <> TipoOrientación.Vertical Then
            Throw New ArgumentException
        End If

        ' reajustar la posición inicial
        If orientación = TipoOrientación.Horizontal Then
            If posicion.X + b.CasillasQueOcupa - 1 > Ancho - 1 Then
                posicion.X = Ancho - 1 - b.CasillasQueOcupa - 1
            End If
        Else
            If posicion.Y + b.CasillasQueOcupa - 1 > Alto - 1 Then
                posicion.Y = Alto - 1 - b.CasillasQueOcupa - 1
            End If
        End If

        ' calcular la caja alrededor del barco
        Dim xInicial As Integer = posicion.X - 1
        Dim yInicial As Integer = posicion.Y - 1
        Dim xFinal As Integer = posicion.X + 1
        Dim yFinal As Integer = posicion.Y + 1
        If orientación = TipoOrientación.Horizontal Then
            xFinal = posicion.X + b.CasillasQueOcupa
        Else
            yFinal = posicion.Y + b.CasillasQueOcupa
        End If
        If xInicial < 0 Then xInicial = 0
        If xFinal > Ancho - 1 Then xFinal = Ancho - 1
        If yInicial < 0 Then yInicial = 0
        If yFinal > Alto - 1 Then yFinal = Alto - 1

        ' comprueba que hay espacio
        For x As Integer = xInicial To xFinal
            For y As Integer = yInicial To yFinal
                'Debug.Print("Comprobando sitio en: " + x.ToString + ", " + y.ToString)
                If _casilla(x, y).Contenido = TipoContenido.Barco Then
                    Return False
                End If
            Next
        Next

        ' coloca el barco
        Dim subParte As Integer = 0
        For x As Integer = posicion.X To _
            posicion.X + IIf(orientación = TipoOrientación.Horizontal, b.CasillasQueOcupa - 1, 0)
            For y As Integer = posicion.Y To _
                posicion.Y + IIf(orientación = TipoOrientación.Vertical, b.CasillasQueOcupa - 1, 0)
                b.Orientación = orientación
                _casilla(x, y).AsignaBarco(b, subParte)
                subParte += 1
                'Debug.Print("Colocando en: " + x.ToString + ", " + y.ToString)
            Next
        Next

        Return True
    End Function

    Public Function DameElÁbaco() As Ábaco
        Dim a = New Ábaco

        For Each b As Barco In _barco
            a.ContabilizaUnBarco(b.Tipo, b.EsHundido())
        Next

        For x As Integer = 0 To Ancho - 1
            For y As Integer = 0 To Alto - 1
                If _casilla(x, y).Disparada Then
                    a.ContabilizaDisparo(_casilla(x, y).EsAcierto)
                End If
            Next
        Next

        Return a
    End Function

    Public Function EsElementoUIAsociadoConCasilla(posicion As Point) As Boolean
        Dim c = GetInfoCasilla(posicion)
        Return c.EsElementoUI
    End Function

    Public Sub AsociaElementoUI(ByVal posicion As Point, ByVal pb As PictureBox)
        Dim c = GetInfoCasilla(posicion)
        c.AsociaElementoUI(pb)
    End Sub

#Region " Procesa disparos "

    ''' <summary>
    ''' Envia el disparo si es tu turno. Si lo envía pasa el turno.
    ''' </summary>
    ''' <param name="posicion"></param>
    ''' <remarks></remarks>
    Public Sub EnviaDisparo(ByVal posicion As Point)
        ' envía el proyectil
        If P2PEncapsulado.EsMiTurno Then
            P2PEncapsulado.SendCediendoTurno(CreaHashDisparo(_host, posicion))
        End If
    End Sub

    Public Sub EnviaInfoImpacto(posicion As Point)
        If _host <> P2PEncapsulado.HostPropio Then
            Return
        End If
        Dim c = GetInfoCasilla(posicion)
        If c.HayBarco Then
            P2PEncapsulado.Send(CreaHashInfoImpacto(_host, posicion, c.Barco.IDBarco, c.Barco.Orientación, c.Barco.Tipo, c.SubParteBarco))
        Else
            P2PEncapsulado.Send(CreaHashInfoImpacto(_host, posicion))
        End If
    End Sub

    Public Sub ImpactoEnAgua(posicion As Point)
        Dim c = GetInfoCasilla(posicion)
        c.DisparoEnAgua()
    End Sub

    Public Sub ImpactoEnBarco(ByVal posicion As Point, ByVal idBarco As Integer, ByVal tipoOrientación As TipoOrientación, ByVal tipoBarco As TipoBarco, ByVal subParte As Integer)
        Dim c = GetInfoCasilla(posicion)
        Dim b = _barco.FirstOrDefault(Function(ba)
                                          Return ba.IDBarco = idBarco
                                      End Function)
        If b Is Nothing Or b.Tipo <> tipoBarco Then
            Throw New ArgumentException("Esto debería de ser imposible. Comprueba que has creado todos los barcos en el constructor y en el orden correcto")
        End If
        b.Orientación = tipoOrientación
        c.DisparoEnBarco(b, subParte)
    End Sub
#End Region

End Class
